import fs from 'fs-extra';
import path from 'path';
import { glob } from 'glob';
import chalk from 'chalk';
import { TransformOptions, TransformResult, FileInfo } from './types';
import { PageTransformer } from './transformers/page-transformer';
import { ComponentTransformer } from './transformers/component-transformer';
import { StyleTransformer } from './transformers/style-transformer';
import { ConfigTransformer } from './transformers/config-transformer';

export class Transformer {
  private options: TransformOptions;
  private pageTransformer: PageTransformer;
  private componentTransformer: ComponentTransformer;
  private styleTransformer: StyleTransformer;
  private configTransformer: ConfigTransformer;

  constructor(options: TransformOptions) {
    this.options = options;
    this.pageTransformer = new PageTransformer(options.config);
    this.componentTransformer = new ComponentTransformer(options.config);
    this.styleTransformer = new StyleTransformer(options.config);
    this.configTransformer = new ConfigTransformer(options.config);
  }

  async transform(): Promise<TransformResult> {
    const result: TransformResult = {
      success: true,
      files: [],
      errors: [],
      warnings: []
    };

    try {
      console.log(chalk.blue(`📁 Scanning source directory: ${this.options.sourcePath}`));
      
      // 扫描源文件
      const sourceFiles = await this.scanSourceFiles();
      console.log(chalk.green(`📄 Found ${sourceFiles.length} files to transform`));

      // 创建输出目录
      if (!this.options.dryRun) {
        await fs.ensureDir(this.options.outputPath);
      }

      // 转换文件
      for (const file of sourceFiles) {
        try {
          const transformedFiles = await this.transformFile(file);
          result.files.push(...transformedFiles);
        } catch (error) {
          const errorMsg = `Failed to transform ${file}: ${error}`;
          result.errors.push(errorMsg);
          console.error(chalk.red(errorMsg));
        }
      }

      // 生成Taro项目配置文件
      if (!this.options.dryRun) {
        await this.generateTaroConfig();
      }

      // 生成类型定义
      if (this.options.config.output.generateTypes) {
        await this.generateTypes(result.files);
      }

      // 生成文档
      if (this.options.config.output.generateDocs) {
        await this.generateDocs(result.files);
      }

    } catch (error) {
      result.success = false;
      result.errors.push(`Transformation failed: ${error}`);
      throw error;
    }

    return result;
  }

  private async scanSourceFiles(): Promise<string[]> {
    const patterns = [
      '**/*.js',
      '**/*.wxml',
      '**/*.wxss',
      '**/*.json'
    ];

    const files: string[] = [];
    
    for (const pattern of patterns) {
      const matches = await glob(pattern, {
        cwd: this.options.sourcePath,
        ignore: this.options.config.ignore,
        absolute: true
      });
      
      files.push(...matches);
    }

    return files;
  }

  private async transformFile(filePath: string): Promise<FileInfo[]> {
    const relativePath = path.relative(this.options.sourcePath, filePath);
    const ext = path.extname(filePath);
    const transformedFiles: FileInfo[] = [];

    console.log(chalk.cyan(`🔄 Transforming: ${relativePath}`));

    try {
      const content = await fs.readFile(filePath, 'utf8');

      switch (ext) {
        case '.js':
          const jsResult = await this.pageTransformer.transform(content, relativePath);
          if (jsResult) {
            transformedFiles.push({
              path: this.getOutputPath(relativePath, '.js', '.tsx'),
              content: jsResult,
              type: 'tsx'
            });
          }
          break;

        case '.wxml':
          const wxmlResult = await this.componentTransformer.transformWXML(content, relativePath);
          if (wxmlResult) {
            transformedFiles.push({
              path: this.getOutputPath(relativePath, '.wxml', '.tsx'),
              content: wxmlResult,
              type: 'tsx'
            });
          }
          break;

        case '.wxss':
          const wxssResult = await this.styleTransformer.transformWXSS(content, relativePath);
          if (wxssResult) {
            transformedFiles.push({
              path: this.getOutputPath(relativePath, '.wxss', '.css'),
              content: wxssResult,
              type: 'css'
            });
          }
          break;

        case '.json':
          const jsonResult = await this.configTransformer.transformJSON(content, relativePath);
          if (jsonResult) {
            transformedFiles.push({
              path: this.getOutputPath(relativePath, '.json', '.json'),
              content: jsonResult,
              type: 'json'
            });
          }
          break;
      }

      // 写入文件
      if (!this.options.dryRun) {
        for (const file of transformedFiles) {
          const fullPath = path.join(this.options.outputPath, file.path);
          await fs.ensureDir(path.dirname(fullPath));
          await fs.writeFile(fullPath, file.content, 'utf8');
        }
      }

    } catch (error) {
      throw new Error(`Failed to transform ${relativePath}: ${error}`);
    }

    return transformedFiles;
  }

  private getOutputPath(relativePath: string, oldExt: string, newExt: string): string {
    const dir = path.dirname(relativePath);
    const name = path.basename(relativePath, oldExt);
    return path.join(dir, `${name}${newExt}`);
  }

  private async generateTaroConfig(): Promise<void> {
    const configContent = this.configTransformer.generateTaroConfig();
    const configPath = path.join(this.options.outputPath, 'config/index.js');
    
    await fs.ensureDir(path.dirname(configPath));
    await fs.writeFile(configPath, configContent, 'utf8');
    
    console.log(chalk.green('✅ Generated Taro config'));
  }

  private async generateTypes(files: FileInfo[]): Promise<void> {
    // 生成类型定义文件
    const typesContent = this.generateTypesContent(files);
    const typesPath = path.join(this.options.outputPath, 'types/index.d.ts');
    
    await fs.ensureDir(path.dirname(typesPath));
    await fs.writeFile(typesPath, typesContent, 'utf8');
    
    console.log(chalk.green('✅ Generated TypeScript types'));
  }

  private async generateDocs(files: FileInfo[]): Promise<void> {
    // 生成转换文档
    const docsContent = this.generateDocsContent(files);
    const docsPath = path.join(this.options.outputPath, 'TRANSFORMATION.md');
    
    await fs.writeFile(docsPath, docsContent, 'utf8');
    
    console.log(chalk.green('✅ Generated transformation documentation'));
  }

  private generateTypesContent(files: FileInfo[]): string {
    return `// Auto-generated types for Taro project
export interface PageProps {
  // Add your page props here
}

export interface ComponentProps {
  // Add your component props here
}

// Add more type definitions as needed
`;
  }

  private generateDocsContent(files: FileInfo[]): string {
    return `# Taro Transformation Documentation

This document describes the transformation from WeChat miniprogram to Taro project.

## Transformed Files

Total files transformed: ${files.length}

### File Types:
- JavaScript files: ${files.filter(f => f.type === 'tsx').length}
- Style files: ${files.filter(f => f.type === 'css').length}
- Config files: ${files.filter(f => f.type === 'json').length}

## Next Steps

1. Install Taro dependencies
2. Configure your development environment
3. Test the transformed components
4. Customize as needed

## Notes

- Some manual adjustments may be required
- Review the generated code for accuracy
- Test thoroughly before deployment
`;
  }
} 